/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright (C) 1998-2009  Gerwin Klein <lsf@jflex.de>                    *
 * All rights reserved.                                                    *
 *                                                                         *
 * License: BSD                                                            *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* Java 1.2 language lexer specification */

/* Use together with unicode.flex for Unicode preprocesssing */
/* and java12.cup for a Java 1.2 parser                      */

/* Note that this lexer specification is not tuned for speed.
   It is in fact quite slow on integer and floating point literals, 
   because the input is read twice and the methods used to parse
   the numbers are not very fast. 
   For a production quality application (e.g. a Java compiler) 
   this could be optimized */

package scanner;

import scanner.Token;
import scanner.Scanner;

%%

%public
%class LexScanner
%implements Scanner
%type Token

%unicode

%init{
    this.zzReader = in;
    try{
        nextToken = yylex();
    }
    catch(Exception e){
        System.err.println("Error in constructor: " + e);
    }
%init}

%{
   private Token nextToken;

  StringBuilder string = new StringBuilder();
  
  private Token token(Token.TokenType type) {
    return new Token(type);
  }
  
  private Token token(Token.TokenType type, Object data) {
    return new Token(type, data);
  }

    public Token getNextToken(){
        Token newToken = null;
        try{
            newToken = new Token(nextToken.getType(), nextToken.getData());
            if(nextToken.getType() != Token.TokenType.EOF_TOKEN){
                    nextToken = null;
                    nextToken = yylex();
            }
        }
        catch(Exception e){
            System.err.println("ERROR: " + e);
        }

        return newToken;
    }

    public Token viewNextToken(){
            return nextToken;
    }
%}

/* main character classes */
LineTerminator = \r|\n|\r\n

WhiteSpace = {LineTerminator} | [ \t\f]

/* comments */
Comment = {TraditionalComment}

TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/"

/* identifiers */
Identifier = [:jletter:]+

/* integer literals */
DecIntegerLiteral = 0 | [1-9][0-9]*

%%

<YYINITIAL> {

  /* keywords */
  "else"                         { return token(Token.TokenType.ELSE_TOKEN); }
  "int"                          { return token(Token.TokenType.INT_TOKEN); }
  "if"                           { return token(Token.TokenType.IF_TOKEN); }
  "return"                       { return token(Token.TokenType.RETURN_TOKEN); }
  "void"                         { return token(Token.TokenType.VOID_TOKEN); }
  "while"                        { return token(Token.TokenType.WHILE_TOKEN); }
  
  /* separators */
  "("                            { return token(Token.TokenType.OPAREN_TOKEN); }
  ")"                            { return token(Token.TokenType.CPAREN_TOKEN); }
  "{"                            { return token(Token.TokenType.OCURLY_TOKEN); }
  "}"                            { return token(Token.TokenType.CCURLY_TOKEN); }
  "["                            { return token(Token.TokenType.OBRACE_TOKEN); }
  "]"                            { return token(Token.TokenType.CBRACE_TOKEN); }
  ";"                            { return token(Token.TokenType.SEMICOLON_TOKEN); }
  ","                            { return token(Token.TokenType.COMMA_TOKEN); }
  
  /* operators */
  "="                            { return token(Token.TokenType.ASSIGN_TOKEN); }
  ">"                            { return token(Token.TokenType.GT_TOKEN); }
  "<"                            { return token(Token.TokenType.LT_TOKEN); }
  "=="                           { return token(Token.TokenType.EQUALITY_TOKEN); }
  "<="                           { return token(Token.TokenType.LTE_TOKEN); }
  ">="                           { return token(Token.TokenType.GTE_TOKEN); }
  "!="                           { return token(Token.TokenType.NOT_EQUAL_TOKEN); }
  "+"                            { return token(Token.TokenType.PLUS_TOKEN); }
  "-"                            { return token(Token.TokenType.MINUS_TOKEN); }
  "*"                            { return token(Token.TokenType.MULT_TOKEN); }
  "/"                            { return token(Token.TokenType.DIV_TOKEN); }
  
  {DecIntegerLiteral}            { return token(Token.TokenType.NUM_TOKEN, new Integer(yytext())); }
  
  /* comments */
  {Comment}                      { /* ignore */ }

  /* whitespace */
  {WhiteSpace}                   { /* ignore */ }

  /* identifiers */ 
  {Identifier}                   { return token(Token.TokenType.ID_TOKEN, yytext()); }  
}

/* error fallback */
[^]                              { return token(Token.TokenType.ERROR_TOKEN, "ERROR parsing. " + yytext() + " was parsed."); }
<<EOF>>                          { return token(Token.TokenType.EOF_TOKEN); }